
package de.uni.wuppertal.server.http;

import java.io.File;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.security.MessageDigest;

import de.uni.wuppertal.server.ErrorLogEntry;
import de.uni.wuppertal.server.ServerInfo;
import de.uni.wuppertal.server.ui.MainWindow;

/**
 * @author Martin Schröder
 * @author Patrik Nordsiek
 */
public class HTTPServer implements ServerInfo
{
	private String name;
	private int port;
	private String rootDirectory;
	
	private MainWindow window;
	
	private boolean terminate = false;
	
	private ServerSocket socket;
	
	protected String[] supportedMethods =
	{
		"HEAD", "GET"
	};
	
	public static final String CRLF = "\r\n";
	
	public HTTPServer()
	{
		window = MainWindow.getInstance();
	}
	
	public static String htmlEntities(String source)
	{
		String r = source;
		
		if(r != null)
		{
			return r.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
		}
		
		return "";
	}
	
	public static String generateFileETag(File file)
	{
		try
		{
			String plainText = "123456";
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			
			md5.reset();
			md5.update(file.getAbsolutePath().getBytes());
			
			StringBuffer buffer = new StringBuffer();
			byte[] digest = md5.digest();
			
			for(int i = 0; i < digest.length; i++)
			{
				plainText = Integer.toHexString(0xFF & digest[i]);
				
				if(plainText.length() < 2)
				{
					plainText = "0" + plainText;
				}
				
				buffer.append(plainText);
			}
			
			return buffer.toString();
		}
		catch(Throwable e)
		{
			MainWindow.getInstance().log(new ErrorLogEntry(e));
			
			return null;
		}
	}
	
	public String[] getSupportedMethods()
	{
		return supportedMethods;
	}
	
	@Override
	public void run()
	{
		try
		{
			terminate = false;
			
			socket = new ServerSocket(port);
			socket.setSoTimeout(100);
			
			window.incrementActiveServerInstance();
			
			while(true)
			{
				try
				{
					Socket clientSocket = socket.accept();
					
					Thread st = new Thread(new HTTPServerThread(this, clientSocket));
					st.setDaemon(true);
					st.start();
				}
				catch(SocketTimeoutException ste)
				{
					if(terminate)
					{
						break;
					}
				}
			}
		}
		catch(Throwable e)
		{
			window.log(new ErrorLogEntry(e));
			
			e.printStackTrace();
		}
		finally
		{
			window.decrementActiveServerInstance();
			
			try
			{
				socket.close();
			}
			catch(Throwable e)
			{
				window.log(new ErrorLogEntry(e));
				
				e.printStackTrace();
			}
			finally
			{
				socket = null;
			}
		}
	}
	
	@Override
	public int getPort()
	{
		return port;
	}
	
	@Override
	public synchronized void setPort(int port)
	{
		this.port = port;
	}
	
	@Override
	public String getName()
	{
		return name;
	}
	
	@Override
	public synchronized void setName(String name)
	{
		this.name = name;
	}
	
	@Override
	public synchronized void stopServer()
	{
		terminate = true;
	}
	
	@Override
	public String getRootDirectory()
	{
		return rootDirectory;
	}
	
	@Override
	public synchronized void setRootDirectory(String rootDirectory)
	{
		this.rootDirectory = rootDirectory;
	}
	
	@Override
	public int compareTo(ServerInfo info)
	{
		return name.compareToIgnoreCase(info.getName());
	}
}
